/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/


#include "MkTcpServer.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkEventPool.h"
#include "MkTcp/MkTcpSession.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

#ifdef MkUt
#define TcpSessionCheckSec  0
#else
#define TcpSessionCheckSec  30
#endif
CMkTcpServer::CMkTcpServer(CMkEventPool* pEventPool, CMkTimer* pTimer, Uint32 MaxConnections)
    : CMkSocket(TcpListener, pEventPool->GetFreeEvent(), pTimer)
    , m_EventPool(pEventPool)
    , m_pTimer(pTimer)
    , m_MaxConnections(MaxConnections)
{
    m_pTimer->AddTimer([this]() {
        CheckSession();
    }, TcpSessionCheckSec * 1000, m_CheckTimer);
}

Uint32 CMkTcpServer::StartServer(Uint16 Port, const MkString& Ip/* =""*/)
{
    Uint32  ErrorCode = Create();
    MkCheckErrorLog(ErrorCode, "create socket failed\n");
    ErrorCode = Bind(Port, Ip);
    MkCheckErrorLog(ErrorCode, "bind socket failed\n");
    return Listen();
}

Uint32 CMkTcpServer::StopServer()
{
    GetTimer()->DeleteTimer(m_CheckTimer);
    Close();
    MapTcpSession TmpMapSession;
    m_SessionLock.WLock();
    TmpMapSession = m_MapTcpSession;
    m_MapTcpSession.clear();
    m_SessionLock.WUnlock();
    MapTcpSession::iterator it = TmpMapSession.begin();
    for (; it != TmpMapSession.end(); it++) {
        MkDelete(it->second);
    }
    return NoneError;
}

void CMkTcpServer::CheckSession()
{
    CMkTime NowTime = NowMkTime;
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.begin();
    for (; it != m_MapTcpSession.end(); it++) {
        it->second->Check(NowTime);
    }
    m_SessionLock.RUnlock();
}

Uint32 CMkTcpServer::OnAccept()
{
    Uint32 ConnectionCount = 0;
    m_SessionLock.RLock();
    ConnectionCount = m_MapTcpSession.size();
    m_SessionLock.RUnlock();
    if (ConnectionCount >= m_MaxConnections) {
        MkErrorLog("cur connect count:%d  maxconnect count:%d\n", ConnectionCount, m_MaxConnections);
        return UnSupported;
    }
    CMkTcpSession *pSession = CreateNewSession(GetEventPool()->GetFreeEvent(), GetTimer());
    if (!pSession) {
        MkErrorLog("create new session failed\n");
        return MallocFailed;
    }
    Uint32 ErrorCode = Accept(pSession);
    if (NoneError != ErrorCode) {
        MkErrorLog("accect session failed\n");
        delete(pSession);
        return ErrorCode;
    }
    OnSessionAccepted(pSession);
    m_SessionLock.WLock();
    m_MapTcpSession[pSession->GetSessionId()] = pSession;
    ConnectionCount = m_MapTcpSession.size();
    m_SessionLock.WUnlock();
    //MkDebugLog("accept session cur count:%d session:%s\n", ConnectionCount,pSession->GetSessionId().c_str());
    return NoneError;
}

//CMkTcpSession* CMkTcpServer::CreateNewSession(CMkEvent *pEvent, CMkTimer* pTimer)
//{
//    return new CMkTcpSession(pEvent, pTimer, this);
//}

Uint32 CMkTcpServer::OnSessionAccepted(CMkTcpSession *pSession)
{
    return NoneError;
}

Uint32 CMkTcpServer::OnSessionEventRemoved(CMkTcpSession* pSession)
{
    if (!pSession) {
        return InvalidParams;
    }
    m_SessionLock.WLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(pSession->GetSessionId());
    if (it != m_MapTcpSession.end()) {
        m_MapTcpSession.erase(it);
    }
    m_SessionLock.WUnlock();
    MkErrorLog("tcp server on event remove:%p\n", pSession);
    pSession->GetEvent()->AddPipTask([pSession]() {delete pSession; });
    return NoneError;
}

//Uint32 CMkTcpServer::Send(const Uint64& SessionId, const CMkBufferList& BufferList)
//{
//    Uint32 ErrorCode = NoneError;
//    CMkTcpSession* pSession = nullptr;
//    m_SessionLock.RLock();
//    MapTcpSession::iterator it = m_MapTcpSession.find(SessionId);
//    if (it != m_MapTcpSession.end()) {
//        pSession = it->second;
//    }
//    m_SessionLock.RUnlock();
//    if (pSession) {
//        ErrorCode = pSession->Send(BufferList);
//    }
//    return ErrorCode;
//}

Uint32 CMkTcpServer::CloseSession(const Uint64& SessionId)
{
    Uint32 ErrorCode = NoneError;
    CMkTcpSession* pSession = nullptr;
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(SessionId);
    if (it != m_MapTcpSession.end()) {
        pSession = it->second;
    }
    m_SessionLock.RUnlock();
    if (pSession) {
        ErrorCode = pSession->Close();
    }
    return ErrorCode;
}

CMkTcpSession* CMkTcpServer::GetTcpSession(const Uint64& SessionId)
{
    CMkTcpSession* pSession = nullptr;
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(SessionId);
    if (it != m_MapTcpSession.end()) {
        pSession = it->second;
    }
    m_SessionLock.RUnlock();
    return pSession;
}

CMkTcpServer::~CMkTcpServer()
{
    StopServer();
}